/*
snake.cpp
*/
#include <termios.h>	// getchar() 关闭缓冲区
#include <time.h>
#include <string>
#include <queue>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include "./kbhit.cpp"

using namespace std;

typedef struct Position{
	int x; 
	int y;
	Position operator+ (Position& u) const {
		return {x + u.x, y + u.y};
	}
} posit;

enum Dire {
	Up,
	Down,
	Left,
	Right
} ;

posit mv[] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};

const int LENGTH  = 80;
const int WIDTH 	= 20;

const char space 	= ' ';
const char wall 	= '=';
const char Snake	= '0';
const char Apple 	= '*';
const char Head 	= '@';
const char* AppleShow = "";


const int initLength = 3;


char map[WIDTH][LENGTH];

queue<posit> snake;
// 当前蛇头方向
Dire dire;
// 输入的蛇头方向
Dire td;
// 蛇头
posit head;
// 蛇尾
posit tail;



void show() {
	system("clear");
	for (int i = 0; i < WIDTH; ++ i ) {
		for (int j = 0; j < LENGTH; ++ j ) {
			if (Apple == map[i][j])
				cout << AppleShow ;
			else
				cout << map[i][j] ;
		}
		cout << endl;
	}
}

void apple() {

	int x, y;
	do {
		x = rand()%WIDTH;
		y = rand()%LENGTH;
	} while (map[x][y] != space);
	map[x][y] = Apple;
}


void init() {
	// 随机种子
	srand((unsigned int)time(NULL));
	// 关闭缓冲
	system("stty -icanon");

	// 初始化地图
	for (int i = 0; i < WIDTH; ++ i ) {
		for (int j = 0; j < LENGTH; ++ j ) {
			if ( i == 0 || j == 0 || i == WIDTH - 1 || j == LENGTH - 1) 
			 	map[i][j] = wall;
			else 
				map[i][j] = space;	
		}
	}

	// 初始化蛇
	int tx = WIDTH / 2;
	int ty = LENGTH / 2;

	for (int i = 0; i < initLength; ++ i) {
		// 身体
		snake.push({tx, i + ty});
		map[tx][i + ty] = Snake;
		// 头
		if (i == initLength - 1) 
			head = {tx, i + ty};
	}

	// 初始化方向
	dire = td = Right;

	// 初始化Apple
	apple();	
	
	show();
}

bool move() {
	if (td == Up || td == Down) {
		if (dire == Left || dire == Right) {
			dire = td;
		}
	}

	if (td == Left || td == Right) {
		if (dire == Up || dire == Down) {
			dire = td;
		}
	}
	// 此时 头 是 '@' 先改成 '0'
	map[head.x][head.y] = Snake;
	head = head + mv[dire];
	if (map[head.x][head.y] == wall || map[head.x][head.y] == Snake) {
		return false;
	}

	if (map[head.x][head.y] != Apple) {
		tail = snake.front();
		snake.pop();
		map[tail.x][tail.y] = space;
	} else {
		apple();
	}

	snake.push(head);
	map[head.x][head.y] = Head;

	show();
	return true;
}

// 转换 
enum Dire transf(char ch) {
 switch (ch) {
	case 'k':
		 return Up;
	case 'j':
		 return Down;
	case 'h':
		 return Left;
	case 'l':
		 return Right;
 }
 return dire;
}

int main() {
	init();
	char ch;
	double tim = 5.0;
	const int cnt = 10;

	bool status = true;
	
	while ( status ) {
		system(string("sleep " + to_string(1 / tim)).c_str());
		if ( _kbhit()) {
			fflush(stdin);
			ch = getchar();
			if ('q' == ch) return 0;
			td = transf(ch);
		}
		if (move() == false) {
			status = false;
			break;
		}
		show();
	}
	cout << "score: " << snake.size() << endl;
	return 0;
}
